const vscode = require("vscode");
const path = require("path");
const moment = require("moment");
const fs = require("fs");
const sharp = require("sharp");
const { spawn } = require("child_process");
const qnUpload = require("./lib/upload");

exports.activate = (context) => {
  const disposable = vscode.commands.registerCommand(
    "extension.screenshotUploadQiniu",
    () => {
      start();
    }
  );
  context.subscriptions.push(disposable);
};

// 当您的扩展被停用时，会调用此方法
exports.deactivate = () => {};

async function start() {
  // 获取当前编辑文件
  let editor = vscode.window.activeTextEditor;
  if (!editor) {
    vscode.window.showInformationMessage("请在文件编辑状态时使用");
    return;
  }

  let fileUri = editor.document.uri;
  if (!fileUri) return;

  if (fileUri.scheme === "untitled") {
    vscode.window.showInformationMessage(
      "粘贴图像之前，您需要先保存当前的编辑文件。"
    );
    return;
  }

  let selection = editor.selection;
  let selectText = editor.document.getText(selection);

  if (selectText && !/^[\w\-.]+$/.test(selectText)) {
    vscode.window.showInformationMessage("您选择的文件名无效！");
    return;
  }
  let config = vscode.workspace.getConfiguration("screenshotUploadQiniu");
  let localPath = config["localPath"];
  if (localPath && localPath.length !== localPath.trim().length) {
    vscode.window.showErrorMessage('指定的路径无效。"' + localPath + '"');
    return;
  }

  let filePath = fileUri.fsPath;
  let imagePath = getImagePath(filePath, selectText, localPath);
  const mdFilePath = editor.document.fileName;
  const mdFileName = path.basename(mdFilePath, path.extname(mdFilePath));

  try {
    const createImagePath = await createImageDirWithImagePath(imagePath);
    saveClipboardImageToFileAndGetPath(createImagePath, async (imagePath) => {
      if (!imagePath) return;
      if (imagePath === "no image") {
        vscode.window.showInformationMessage("剪贴板中没有图片！");
        return;
      }

      try {
        const newImagePath = await sharpImage(imagePath, config);
        try {
          const { name, url } = await qnUpload(
            config,
            newImagePath,
            mdFilePath
          );
          vscode.window.showInformationMessage("上传成功!");
          const img = `![${name}](${url})`;
          editor.edit((textEditorEdit) => {
            textEditorEdit.insert(editor.selection.active, img);
          });

          // 是否删除本地文件
          if (config.deleteImageToLocal) {
            unlinkSync(localPath);
          }
        } catch (error) {
          vscode.window.showErrorMessage("上传失败 " + JSON.stringify(error));
          unlinkSync(localPath);
        }
      } catch (error) {
        vscode.window.showErrorMessage("图片压缩失败" + JSON.stringify(error));
      }
    });
  } catch (error) {
    vscode.window.showErrorMessage("创建文件夹失败" + JSON.stringify(error));
  }
}

function unlinkSync(path) {
  try {
    fs.unlinkSync(path);
  } catch (error) {
    vscode.window.showErrorMessage("删除文件失败" + JSON.stringify(error));
  }
}

function getImagePath(filePath, selectText, localPath) {
  // 图片名称
  let imageFileName = "";
  const ext = ".png";
  const suffix = "_original";
  if (!selectText) {
    imageFileName = moment().format("Y-MM-DD-HH-mm-ss") + suffix + ext;
  } else {
    imageFileName = selectText + suffix + ext;
  }

  // 图片本地保存路径
  let folderPath = path.dirname(filePath);
  let imagePath = "";
  if (path.isAbsolute(localPath)) {
    imagePath = path.join(localPath, imageFileName);
  } else {
    imagePath = path.join(folderPath, localPath, imageFileName);
  }

  return imagePath;
}

// 压缩图片, 默认 60
function sharpImage(imagePath, config) {
  return new Promise((resolve, reject) => {
    const toFile = imagePath.split("_")[0] + ".webp";
    const image = sharp(imagePath);
    image
      .metadata()
      .then((metadata) => {
        return (
          image
            // .resize(Math.round(metadata.width / 2))
            .webp({ quality: config.quality })
            .toFile(toFile)
        );
      })
      .then((data) => {
        fs.unlink(imagePath, function (err) {
          if (!err) {
            resolve(toFile);
            return;
          }
          reject(err);
          vscode.window.showErrorMessage(
            "删除元文件失败" + JSON.stringify(err)
          );
        });
      })
      .catch((err) => {
        reject(err);
        vscode.window.showErrorMessage("转换图片失败" + JSON.stringify(err));
      });
  });
}

function createImageDirWithImagePath(imagePath) {
  return new Promise((resolve, reject) => {
    let imageDir = path.dirname(imagePath);
    fs.exists(imageDir, (exists) => {
      if (exists) {
        resolve(imagePath);
        return;
      }
      fs.mkdir(imageDir, (err) => {
        if (err) {
          reject(err);
          return;
        }
        resolve(imagePath);
      });
    });
  });
}

function saveClipboardImageToFileAndGetPath(imagePath, cb) {
  if (!imagePath) return;
  let platform = process.platform;
  if (platform === "win32") {
    // Windows
    const scriptPath = path.join(__dirname, "./lib/pc.ps1");
    const powershell = spawn("powershell", [
      "-noprofile",
      "-noninteractive",
      "-nologo",
      "-sta",
      "-executionpolicy",
      "unrestricted",
      "-windowstyle",
      "hidden",
      "-file",
      scriptPath,
      imagePath,
    ]);
    powershell.on("exit", function (code, signal) {});
    powershell.stdout.on("data", function (data) {
      cb(data.toString().trim());
    });
  } else if (platform === "darwin") {
    // Mac
    let scriptPath = path.join(__dirname, "./lib/mac.applescript");

    let ascript = spawn("osascript", [scriptPath, imagePath]);
    ascript.on("exit", function (code, signal) {});

    ascript.stdout.on("data", function (data) {
      cb(data.toString().trim());
    });
  } else {
    // Linux

    let scriptPath = path.join(__dirname, "./lib/linux.sh");

    let ascript = spawn("sh", [scriptPath, imagePath]);
    ascript.on("exit", function (code, signal) {});

    ascript.stdout.on("data", function (data) {
      let result = data.toString().trim();
      if (result == "no xclip") {
        vscode.window.showInformationMessage(
          "You need to install xclip command first."
        );
        return;
      }
      cb(result);
    });
  }
}
